

import time

import dexen

import constants

class Fitness(object):
    def __init__(self, inds):
        self.inds = inds

    def _on_pareto_front(self, ind, inds):
        for ind2 in inds:
            if ind2.dominates(ind):
                return False
        return True

    def _extract_pareto_front(self, inds):
        pareto_front = []
        non_pareto_front = []
        
        for ind in inds:
            if self._on_pareto_front(ind, inds):
                pareto_front.append(ind)
            else:
                non_pareto_front.append(ind)
        return pareto_front, non_pareto_front            

    def calc(self):
        fitness = 1
        inds = self.inds
        while len(inds) > 0:
            pareto_front, non_pareto_front = self._extract_pareto_front(inds)
            print "pareto", len(pareto_front), "non pareto", len(non_pareto_front)
            time.sleep(1)
            for ind in pareto_front:
                ind.fitness = fitness
            fitness += 1
            inds = non_pareto_front

def select(inds):
    inds = sorted(inds, key=lambda ind: ind.fitness)
    size = len(inds)
    return inds[:size/2], inds[size/2:]

def create_new_gen(inds):
    assert len(inds) % 2 == 0
    
    new_gen = []
    
    for i in range(0, len(inds), 2):
        child1, child2 = inds[i].reproduce(inds[i+1])
        child1.archive_data("birth_time.txt", time.time())
        child2.archive_data("birth_time.txt", time.time())
        new_gen.append(child1)
        new_gen.append(child2)
    
    return new_gen

class FeedbackTask(dexen.Task):
    def __initialize__(self):
        pass
    
    def __isvalid__(self, ind):
        return ind.score_daylight != None and ind.score_energy != None
       
    def __execute__(self, inds=[]):
        fitness = Fitness(inds)
        fitness.calc()
        
        alive_inds, dead_inds = select(inds)
    
        print "Alive ones"
        for ind in alive_inds:
            print ind

        print "Dead ones"
        for ind in dead_inds:
            print ind
        
        for ind in dead_inds:
            ind.kill()
            ind.archive_data("death_time.txt", time.time())
        
        new_gen = create_new_gen(alive_inds)
        return inds + new_gen

#===============================================================================
# TESTING 
#===============================================================================
import myind
import random

def create_ind(daylight, energy):
    ind = myind.MyIndividual()
    ind.score_daylight = daylight
    ind.score_energy = energy
    return ind

def test():
    inds = []
    for _ in range(4):
        ind = create_ind(random.randint(1, 100), random.randint(1, 100))
        inds.append(ind)
    
    fitness = Fitness(inds)
    fitness.calc()
    
    for ind in inds:
        print ind
        

def test2():
    inds = []
    inds.append(create_ind(76, 76))
    inds.append(create_ind(99, 58))
    inds.append(create_ind(43, 72))
    inds.append(create_ind(44, 85))
    
    fitness = Fitness(inds)
    fitness.calc()
    
    for ind in inds:
        print ind
    
   
if __name__ == "__main__":
    test2()


        